import levelData from '@level/春天.json';
// Define the structure of our level data based on the JSON
interface Position {
  x: number;
  y: number;
  z: number;
}

interface PathPoint {
  time: string;
  timeInSeconds: number;
  percentage: number;
  position: Position;
  direction: string;
}

interface LevelData {
  songName: string;
  speed: number;
  totalDuration: number;
  path: PathPoint[];
}

/**
 * Manages the game state and logic for the Dancing Line level.
 */
class MyGame {
  private cube: GameEntity;
  private readonly levelData: LevelData;
  private startTime: number = 0;
  private currentPathIndex: number = 0;
  private gameLoopInterval?: ReturnType<typeof setInterval>;

  constructor(levelData: LevelData) {
    if (!levelData || !levelData.path || levelData.path.length === 0) {
      throw new Error('Invalid level data provided.');
    }
    this.levelData = levelData;
    this.createPathMarkers();
    this.cube = this.createCube();
    this.setupPlayerCamera();
  }

  /**
   * Creates visual markers for each point in the level path.
   */
  private createPathMarkers() {
    console.log(`Creating ${this.levelData.path.length} path markers...`);

    for (const point of this.levelData.path) {
      world.createEntity({
        mesh: 'mesh/方块.vb', // Using a cube mesh for the marker
        position: new GameVector3(
          point.position.x,
          point.position.y,
          point.position.z
        ),
        meshScale: new GameVector3(0.01, 0.01, 0.01), // Make the markers small
        collides: false, // Markers should not have collision
        fixed: true,
        gravity: false,
      });
    }

    console.log('Path markers created successfully.');
  }

  /**
   * Creates the main cube entity and places it at the start of the path.
   */
  private createCube(): GameEntity {
    const startPosition = this.levelData.path[0].position;
    const cube = world.createEntity({
      mesh: 'mesh/方块.vb',
      position: new GameVector3(
        startPosition.x,
        startPosition.y,
        startPosition.z
      ),
      collides: true,
      fixed: true,
      gravity: false,
    });
    if (!cube) {
      throw new Error('Failed to create the cube entity.');
    }
    return cube;
  }

  /**
   * Configures the camera for joining players to follow the cube.
   */
  private setupPlayerCamera() {
    world.onPlayerJoin(async ({ entity }) => {
      entity.player.cameraMode = GameCameraMode.RELATIVE;
      entity.player.cameraPosition = new GameVector3(-5, 5, -5);
      entity.player.cameraEntity = this.cube;
      entity.player.canFly = false;
      entity.player.disableInputDirection = GameInputDirection.BOTH;
    });
  }

  /**
   * Starts the game, plays the music, and begins the update loop.
   */
  public start() {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    world.sound(`audio/${this.levelData.songName}` as any);
    this.startTime = Date.now();
    this.gameLoopInterval = setInterval(() => this.update(), 10);
  }

  /**
   * The main game loop, called at a fixed interval.
   */
  private update() {
    const elapsedTime = (Date.now() - this.startTime) / 1000;

    // Check if we've finished the path
    if (this.currentPathIndex >= this.levelData.path.length - 1) {
      const endPoint = this.levelData.path[this.levelData.path.length - 1];
      this.cube.position = new GameVector3(
        endPoint.position.x,
        endPoint.position.y,
        endPoint.position.z
      );
      if (this.gameLoopInterval) {
        clearInterval(this.gameLoopInterval);
      } // Stop the loop
      return;
    }

    // Move to the next path segment if the time is right
    const nextPoint = this.levelData.path[this.currentPathIndex + 1];
    if (elapsedTime >= nextPoint.timeInSeconds) {
      this.currentPathIndex++;
    }

    // Recalculate segment points in case the index changed
    const startPoint = this.levelData.path[this.currentPathIndex];
    const endPoint = this.levelData.path[this.currentPathIndex + 1];

    // Interpolate the cube's position between the start and end points
    const segmentDuration = endPoint.timeInSeconds - startPoint.timeInSeconds;
    const timeInSegment = elapsedTime - startPoint.timeInSeconds;
    const segmentProgress =
      segmentDuration > 0
        ? Math.max(0, Math.min(1, timeInSegment / segmentDuration))
        : 1;

    this.cube.position.x =
      startPoint.position.x +
      (endPoint.position.x - startPoint.position.x) * segmentProgress;
    this.cube.position.y =
      startPoint.position.y +
      (endPoint.position.y - startPoint.position.y) * segmentProgress;
    this.cube.position.z =
      startPoint.position.z +
      (endPoint.position.z - startPoint.position.z) * segmentProgress;

    this.createTrailEffect();
  }

  /**
   * Creates a visual trail behind the moving cube.
   */
  private createTrailEffect() {
    const clone = world.createEntity({
      mesh: 'mesh/方块.vb',
      position: this.cube.position.clone(),
      meshScale: new GameVector3(0, 0, 0),
      collides: true,
      fixed: true,
      gravity: false,
    });

    if (clone) {
      setTimeout(() => {
        clone.meshScale = this.cube.meshScale.clone();
      }, 100);
      setTimeout(() => {
        clone.destroy();
      }, 3000);
    }
  }
}

// Instantiate and start the game
try {
  const game = new MyGame(levelData);
  game.start();
} catch (error) {
  console.error('Failed to initialize and start the game:', error);
}
